if ENEIDA_UTIL_INCLUDE = 'DATA'

; OpenGL defines
GL_COLOR_BUFFER_BIT = 0x00004000
GL_DEPTH_BUFFER_BIT = 0x00000100
GL_VERTEX_PROGRAM_ARB = 0x8620
GL_FRAGMENT_PROGRAM_ARB = 0x8804
GL_PROGRAM_FORMAT_ASCII_ARB = 0x8875
GL_ARRAY_BUFFER = 0x8892
GL_ELEMENT_ARRAY_BUFFER = 0x8893
GL_STATIC_DRAW = 0x88E4
GL_BUFFER_GPU_ADDRESS_NV = 0x8F1D
GL_READ_ONLY = 0x88B8
GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV = 0x8F1E
GL_ELEMENT_ARRAY_UNIFIED_NV = 0x8F1F
GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV = 0x8F20
GL_ELEMENT_ARRAY_ADDRESS_NV = 0x8F29
GL_FALSE = 0
GL_TRUE = 1
GL_TRIANGLES = 0x0004
GL_UNSIGNED_BYTE = 0x1401
GL_UNSIGNED_INT = 0x1405
GL_FLOAT = 0x1406
GL_DEPTH_TEST = 0x0B71
GL_FRONT_AND_BACK = 0x0408
GL_LINE = 0x1B01
GL_FILL = 0x1B02
GL_TEXTURE0 = 0x84C0
GL_TEXTURE1 = 0x84C1
GL_TEXTURE2 = 0x84C2
GL_TEXTURE3 = 0x84C3
GL_TEXTURE4 = 0x84C4
GL_TEXTURE5 = 0x84C5
GL_TEXTURE6 = 0x84C6
GL_TEXTURE7 = 0x84C7
GL_TEXTURE_2D = 0x0DE1
GL_NEAREST = 0x2600
GL_LINEAR = 0x2601
GL_NEAREST_MIPMAP_NEAREST = 0x2700
GL_LINEAR_MIPMAP_NEAREST = 0x2701
GL_NEAREST_MIPMAP_LINEAR = 0x2702
GL_LINEAR_MIPMAP_LINEAR = 0x2703
GL_TEXTURE_MAG_FILTER = 0x2800
GL_TEXTURE_MIN_FILTER = 0x2801
GL_TEXTURE_WRAP_S = 0x2802
GL_TEXTURE_WRAP_T = 0x2803
GL_CLAMP_TO_EDGE = 0x812F
GL_RGB = 0x1907
GL_RGBA = 0x1908
GL_RGB8 = 0x8051

; OpenGL functions
_func_define glClear
_func_define glGenProgramsARB
_func_define glBindProgramARB
_func_define glGenBuffers
_func_define glBindBuffer
_func_define glNamedBufferDataEXT
_func_define glEnable
_func_define glEnableClientState
_func_define glPolygonMode
_func_define glDrawArrays
_func_define glDrawElements
_func_define glBufferData
_func_define glBufferAddressRangeNV
_func_define glVertexAttribFormatNV
_func_define glGetBufferParameterui64vNV
_func_define glGetNamedBufferParameterui64vNV
_func_define glMakeBufferResidentNV
_func_define glMakeNamedBufferResidentNV
_func_define glEnableVertexAttribArray
_func_define glProgramLocalParameters4fvEXT
_func_define glNamedProgramLocalParameters4fvEXT
_func_define glProgramStringARB
_func_define glNamedProgramStringEXT
_func_define glActiveTexture
_func_define glGenTextures
_func_define glBindTexture
_func_define glBindMultiTextureEXT
_func_define glTextureParameteriEXT
_func_define glTextureImage2DEXT
_func_define glGetError

; libc defines
CLOCKS_PER_SEC = 1000000
RAND_MAX = 2147483647

; libc functions
_func_define clock
_func_define time
_func_define exit
_func_define printf
_func_define malloc
_func_define rand
_func_define srand

align 8

_x_display dq 0
_x_window dq 0
_gl_lib dq 0
_gl_context dq 0

_XPending dq 0
_XNextEvent dq 0
_glXGetProcAddress dq 0
_glXSwapBuffers dq 0

_motif_wm_hints dq 2,0,0,0,0
_glx_fb_attribs dd 0x8011,0x0000001,0x8010,0x0000001,5,1,8,8,9,8,10,8,12,24,13,8,0

_str_libGL db 'libGL.so.1',0
_str_XOpenDisplay db 'XOpenDisplay',0
_str_XCloseDisplay db 'XCloseDisplay',0
_str_XRootWindow db 'XRootWindow',0
_str_XCreateColormap db 'XCreateColormap',0
_str_XCreateWindow db 'XCreateWindow',0
_str_XMapWindow db 'XMapWindow',0
_str_XInternAtom db 'XInternAtom',0
_str_XChangeProperty db 'XChangeProperty',0
_str_XMoveWindow db 'XMoveWindow',0
_str_XPending db 'XPending',0
_str_XNextEvent db 'XNextEvent',0
_str_glXChooseFBConfig db 'glXChooseFBConfig',0
_str_glXGetVisualFromFBConfig db 'glXGetVisualFromFBConfig',0
_str_glXCreateContext db 'glXCreateContext',0
_str_glXDestroyContext db 'glXDestroyContext',0
_str_glXMakeCurrent db 'glXMakeCurrent',0
_str_glXGetProcAddress db 'glXGetProcAddress',0
_str_glXSwapBuffers db 'glXSwapBuffers',0
_str_motif_wm_hints db '_MOTIF_WM_HINTS',0

else if ENEIDA_UTIL_INCLUDE = 'CODE'

macro _func_define func {
align 8
func dq 0
align 8
_str_#func db `func,0
}
macro _func_load lib,func {
    mov rdi,lib
    mov rsi,_str_#func
    call [dlsym]
    mov [func],rax
}
macro _gl_func_load name {
    mov rdi,_str_#name
    call [_glXGetProcAddress]
    mov [name],rax
}

align 16
window_open:
    push rbp
    mov rbp,rsp
    sub rsp,512
    temp equ rbp-8
    fb_configs_count equ rbp-12
    x_display equ rbp-24
    x_visual_info equ rbp-32
    x_root_window equ rbp-40
    x_window equ rbp-48
    x_win_attribs equ rbp-328
    win_x equ rbp-332
    win_y equ rbp-336
    win_w equ rbp-340
    win_h equ rbp-344
    ; save function parameters
    mov [win_x],edi
    mov [win_y],esi
    mov [win_w],edx
    mov [win_h],ecx
    ; load libGL.so.1
    mov rdi,_str_libGL
    xor esi,esi
    inc esi
    call [dlopen]
    mov [_gl_lib],rax
    ; open display
    mov rdi,[_gl_lib]
    mov rsi,_str_XOpenDisplay
    call [dlsym]
    xor edi,edi
    call rax
    mov [x_display],rax
    ; get root window
    mov rdi,[_gl_lib]
    mov rsi,_str_XRootWindow
    call [dlsym]
    mov rdi,[x_display]
    xor esi,esi
    call rax
    mov [x_root_window],rax
    ; get visual info
    mov rdi,[_gl_lib]
    mov rsi,_str_glXChooseFBConfig
    call [dlsym]
    mov rdi,[x_display]
    xor esi,esi
    mov rdx,_glx_fb_attribs
    lea rcx,[fb_configs_count]
    call rax
    mov [temp],rax
    mov rdi,[_gl_lib]
    mov rsi,_str_glXGetVisualFromFBConfig
    call [dlsym]
    mov rdi,[x_display]
    mov rsi,[temp]
    mov rsi,[rsi]
    call rax
    mov [x_visual_info],rax
    ; set window attributes
    mov rdi,[_gl_lib]
    mov rsi,_str_XCreateColormap
    call [dlsym]
    mov rdi,[x_display]
    mov rsi,[x_root_window]
    mov rdx,[x_visual_info]
    mov rdx,[rdx]
    xor ecx,ecx
    call rax
    mov [x_win_attribs+96],rax
    mov qword [x_win_attribs+72],1
    mov qword [x_win_attribs+8],0
    mov qword [x_win_attribs+24],0
    ; create window
    mov rdi,[_gl_lib]
    mov rsi,_str_XCreateWindow
    call [dlsym]
    lea rdi,[x_win_attribs]
    push rdi
    push (1 shl 1) or (1 shl 3) or (1 shl 13) or (1 shl 11)
    mov rdi,[x_visual_info]
    push qword [rdi+0]
    push 1
    push qword [rdi+20]
    push 0
    mov r9d,[win_h]
    mov r8d,[win_w]
    mov ecx,0
    mov edx,0
    mov rsi,[x_root_window]
    mov rdi,[x_display]
    call rax
    add rsp,48
    mov [x_window],rax
    ; remove window border
    mov rdi,[_gl_lib]
    mov rsi,_str_XInternAtom
    call [dlsym]
    mov rdi,[x_display]
    mov rsi,_str_motif_wm_hints
    xor edx,edx
    inc edx
    call rax
    mov [temp],rax
    mov rdi,[_gl_lib]
    mov rsi,_str_XChangeProperty
    call [dlsym]
    mov r8,_motif_wm_hints
    push 10
    push r8
    xor r9d,r9d
    mov r8d,32
    mov rcx,[temp]
    mov rdx,[temp]
    mov rsi,[x_window]
    mov rdi,[x_display]
    call rax 
    add rsp,16
    ; map window
    mov rdi,[_gl_lib]
    mov rsi,_str_XMapWindow
    call [dlsym]
    mov rdi,[x_display]
    mov rsi,[x_window]
    call rax
    ; move window
    mov rdi,[_gl_lib]
    mov rsi,_str_XMoveWindow
    call [dlsym]
    mov rdi,[x_display]
    mov rsi,[x_window]
    mov edx,[win_x]
    mov ecx,[win_y]
    call rax
    ; create context
    mov rdi,[_gl_lib]
    mov rsi,_str_glXCreateContext
    call [dlsym]
    mov rdi,[x_display]
    mov rsi,[x_visual_info]
    xor edx,edx
    xor ecx,ecx
    inc ecx
    call rax
    mov [temp],rax
    mov [_gl_context],rax
    ; make context current
    mov rdi,[_gl_lib]
    mov rsi,_str_glXMakeCurrent
    call [dlsym]
    mov rdi,[x_display]
    mov rsi,[x_window]
    mov rdx,[temp]
    call rax
    ; load X functions
    mov rdi,[_gl_lib]
    mov rsi,_str_XPending
    call [dlsym]
    mov [_XPending],rax
    mov rdi,[_gl_lib]
    mov rsi,_str_XNextEvent
    call [dlsym]
    mov [_XNextEvent],rax
    ; load GLX functions
    mov rdi,[_gl_lib]
    mov rsi,_str_glXGetProcAddress
    call [dlsym]
    mov [_glXGetProcAddress],rax
    mov rdi,[_gl_lib]
    mov rsi,_str_glXSwapBuffers
    call [dlsym]
    mov [_glXSwapBuffers],rax
    ; load GL commands
    _gl_func_load glClear
    _gl_func_load glGenProgramsARB
    _gl_func_load glBindProgramARB
    _gl_func_load glGenBuffers
    _gl_func_load glBindBuffer
    _gl_func_load glNamedBufferDataEXT
    _gl_func_load glEnable
    _gl_func_load glEnableClientState
    _gl_func_load glPolygonMode
    _gl_func_load glDrawArrays
    _gl_func_load glDrawElements
    _gl_func_load glBufferData
    _gl_func_load glBufferAddressRangeNV
    _gl_func_load glVertexAttribFormatNV
    _gl_func_load glGetBufferParameterui64vNV
    _gl_func_load glGetNamedBufferParameterui64vNV
    _gl_func_load glMakeBufferResidentNV
    _gl_func_load glMakeNamedBufferResidentNV
    _gl_func_load glEnableVertexAttribArray
    _gl_func_load glProgramLocalParameters4fvEXT
    _gl_func_load glNamedProgramLocalParameters4fvEXT
    _gl_func_load glProgramStringARB
    _gl_func_load glNamedProgramStringEXT
    _gl_func_load glActiveTexture
    _gl_func_load glGenTextures
    _gl_func_load glBindTexture
    _gl_func_load glBindMultiTextureEXT
    _gl_func_load glTextureParameteriEXT
    _gl_func_load glTextureImage2DEXT
    _gl_func_load glGetError
    ; load libc functions
    _func_load [_gl_lib],clock
    _func_load [_gl_lib],time
    _func_load [_gl_lib],exit
    _func_load [_gl_lib],printf
    _func_load [_gl_lib],malloc
    _func_load [_gl_lib],rand
    _func_load [_gl_lib],srand
    ; save needed variables
    mov rax,[x_display]
    mov [_x_display],rax
    mov rax,[x_window]
    mov [_x_window],rax
    restore temp,fb_configs_count,x_display,x_visual_info,x_root_window,x_window,x_win_attribs,win_x,win_y,win_w,win_h
    mov rsp,rbp
    pop rbp
    ret

align 16
window_swap:
    push rbp
    mov rbp,rsp
    sub rsp,256
    x_event equ rbp-256
    ; swap
    mov rdi,[_x_display]
    mov rsi,[_x_window]
    call [_glXSwapBuffers]
    ; process window events
      .begin:
    mov rdi,[_x_display]
    call [_XPending]
    test eax,eax
    jz .end
    mov rdi,[_x_display]
    lea rsi,[x_event]
    call [_XNextEvent]
    cmp dword [x_event+0],2
    je .quit
    jmp .begin
      .quit:
    mov eax,1
      .end:
    restore x_event
    mov rsp,rbp
    pop rbp
    ret

align 16
window_close:
    sub rsp,8
    mov rax,[_gl_context]
    test rax,rax
    jz @f
    ; glXMakeCurrent
    mov rdi,[_gl_lib]
    mov rsi,_str_glXMakeCurrent
    call [dlsym]
    mov rdi,[_x_display]
    mov esi,0
    mov edx,0
    call rax
    ; glXDestroyContext
    mov rdi,[_gl_lib]
    mov rsi,_str_glXDestroyContext
    call [dlsym]
    mov rdi,[_x_display]
    mov rsi,[_gl_context]
    call rax
      @@:
    mov rax,[_x_display]
    test rax,rax
    jz @f
    ; close display
    mov rdi,[_gl_lib]
    mov rsi,_str_XCloseDisplay
    call [dlsym]
    mov rdi,[_x_display]
    call rax 
      @@:
    add rsp,8
    ret

end if
